/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sahd.broker;
import sahd.broker.client.ClientMachine;
import sahd.broker.client.ClientProtocol;
import sahd.broker.iONetMessageManager.IONetMessageManager;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;

import sahd.broker.iONetMessageManager.Message;
import sahd.broker.server.ServerMachine;
import sahd.broker.server.ServerProtocol;
import sahd.broker.server.Service;
/**
 *
 * @author Romms
 */
public class Broker implements Observer {

    private IONetMessageManager ioNetMessageManager;
    private String serverProxyIpAddress="192.168.1.67";
    private Message message;

    private final int outPort=7777;
    private final int entryPort=8888;
    private final int SERVICE_RESPONSE_PORT=4444;


    /** Creates new form Broker */

    private RegisteredClientsRepository registeredClientsRepository;
    private RegisteredServersRepository registeredServersRepository;
    private RegisteredServiceRepository registeredServicesRepository;


    public Broker() throws UnknownHostException {
        this.registeredClientsRepository= new RegisteredClientsRepository();
        registeredServersRepository= new RegisteredServersRepository();
        registeredServicesRepository = new RegisteredServiceRepository();
        try {
            ioNetMessageManager = new IONetMessageManager(this,outPort,entryPort,serverProxyIpAddress);
            ioNetMessageManager.startReceivingMessages();
        } catch (UnknownHostException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }




    private void sendMessage(Object content, int protocol){
        try {
            this.ioNetMessageManager.setReceiverIpAddres(message.getSenderIpAddress());
            this.ioNetMessageManager.shipMessage(content, protocol);
        } catch (UnknownHostException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void sendMessage(Object content, int protocol, String receiverIpAddress){
        try {
            this.ioNetMessageManager.setOutPort(SERVICE_RESPONSE_PORT);
            this.ioNetMessageManager.setReceiverIpAddres(receiverIpAddress);
            this.ioNetMessageManager.shipMessage(content, protocol);
        } catch (UnknownHostException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void sendMessage(Object content, int protocol, String receiverIpAddress,
            String originalSourceIp, int serviceRequestedProtocol){
        try {
            this.ioNetMessageManager.setOutPort(SERVICE_RESPONSE_PORT);
            this.ioNetMessageManager.setReceiverIpAddres(receiverIpAddress);
            this.ioNetMessageManager.shipMessage(content, protocol,originalSourceIp,
                    serviceRequestedProtocol);
        } catch (UnknownHostException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void  registerServer(){
        ServerMachine serverMachine;

        serverMachine= (ServerMachine) message.getContent();

        if(this.registeredServersRepository.serverMachineExists(serverMachine.getServerMchingeIpAddres())){
            this.sendMessage("UnsuccesfulRegister", ClientProtocol.UNSUCCESFUL_REGISTER);

        }else{
            this.registeredServersRepository.registerServerMachine((ServerMachine) message.getContent());
            this.sendMessage("SuccesfulRegister", ClientProtocol.SUCCESFUL_REGISTER);
        }
    }

    private void registerService(){
        if(this.registeredServersRepository.serverMachineExists(message.getSenderIpAddress())){
            if(this.registeredServicesRepository.registerService((Service) this.message.getContent())){
                this.sendMessage("SuccesfulRegister",ClientProtocol.SUCCESFUL_REGISTER);
            }
        }
        this.sendMessage("UnSuccesfulRegister", ClientProtocol.UNSUCCESFUL_UNREGISTER);
    }

    private void registerListOfServices(){

        ArrayList<Service> services=(ArrayList<Service>) message.getContent();
        if(this.registeredServersRepository.serverMachineExists(message.getSenderIpAddress())){
            for(int serviceIndex=0;serviceIndex<services.size();serviceIndex++){
                if(this.registeredServicesRepository.registerService(services.get(serviceIndex))){
                    this.sendMessage(services.get(serviceIndex).getServiceName(),
                            ClientProtocol.SUCCESFUL_REGISTER);
                }else{
                    this.sendMessage("UnSuccesfulRegister", ClientProtocol.UNSUCCESFUL_UNREGISTER);
                }
            }
        }
    }

    private void registerClient(){
        ClientMachine clientMachine= (ClientMachine) message.getContent();

        if(this.registeredClientsRepository.clientMachineExists(clientMachine)){
            this.sendMessage("UnsuccesfulRegister", ClientProtocol.UNSUCCESFUL_UNREGISTER);
        }else{
            this.registeredClientsRepository.registerClientMachine((ClientMachine) message.getContent());
            this.sendMessage("SuccesfulRegister", ClientProtocol.SUCCESFUL_REGISTER);
        }
    }

    private void unregisterClient(){
        ClientMachine clientMachine= (ClientMachine) message.getContent();
        if(this.registeredClientsRepository.clientMachineExists(clientMachine)){
            this.registeredClientsRepository.unregisterClientMachine(clientMachine);
            this.sendMessage("Succesful Unregister", ClientProtocol.SUCCESFUL_UNREGISTER);
        }else{
            this.sendMessage("Unsuccesful Unregister", ClientProtocol.UNSUCCESFUL_UNREGISTER);
        }
    }

    private void requestService(){
        if(this.registeredServicesRepository.serviceIsRegistered(message.getProtocol())){

            this.sendMessage(message.getContent(), message.getProtocol(),
                    this.registeredServicesRepository.getService(message.getProtocol()).getServerIpAddress(),
                    message.getOriginalSourceIPAddress(),
                    this.registeredServicesRepository.getService(message.getProtocol()).getServiceCode());
        }
    }


    private void responseRequest() {
        if(this.registeredServicesRepository.serviceIsRegistered(message.getProtocol())){
            this.sendMessage(message.getContent(), message.getProtocol(),
                    this.registeredServicesRepository.getService(message.getProtocol()).getServerIpAddress());
        }
    }

    private void protocolHandler(Message message) throws UnknownHostException, IOException{
        this.message=message;

        switch(this.message.getProtocol()){
            case ServerProtocol.REGISTER_SERVER:
                this.registerServer();
                break;

            case ClientProtocol.REGISTER_CLIENT:
                this.registerClient();
                break;

            case ClientProtocol.UNREGISTER_CLIENT:
                this.unregisterClient();
                break;
            case ServerProtocol.REGISTER_LIST_OF_SERVICES:
                this.registerListOfServices();
                break;

            case ServerProtocol.REGISTER_SERVICE:
                this.registerService();
                break;

            case ClientProtocol.REQUEST_SERVICE:
                this.requestService();
                break;

            case ServerProtocol.RESPONSE_REQUEST:
                this.responseRequest();
                break;

            default:
                this.ioNetMessageManager.shipMessage("Invalid protocol", Protocols.INVALID_PROTOCOL);
        }

    }

    public void update(Observable o, Object arg) {
        try  {
            this.protocolHandler((Message) arg);
        } catch (UnknownHostException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BrokerUI.class.getName()).log(Level.SEVERE, null, ex);
        }


    }

}
